/******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd
 ******************************************************************************
 *  @File Name        : kf8a100fxx_i2c.c
 *  @Author           : ChipON AE/FAE Group
 *  @Date             : 2023-12-19
 *  @HW Version       : KF8A100Fxx
 *  @Lib Version      : V2.0.1
 *  @Description      : This file provides the driver for the i2c module
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd
 *  All rights reserved.
 *
 *  This software is copyright protected and proprietary to
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.
 *****************************************************************************/
/******************************************************************************
 *  |Date        |Version  |Author       |Description
 ******************************************************************************
 *  |2023-12-27  |V2.0     |Wang Junxiong|New creat
 *****************************************************************************/

/******************************************************************************
 **                     QAC Warnings
 *****************************************************************************/
/* PRQA S 0436 EOF #8-bit MCU Features: Direct Write Registers. */
/* PRQA S 1291, 1820, 1821, 1822, 1823, 1851, 1853, 3715, 3757, 3760 EOF #Registers are essentially unsigned numbers. */
/* PRQA S 2754 EOF #Level 7 problem due to unsupported assembly instructions. */
/* PRQA S 3768, 3771, 4130, 4393, 4434, 4443, 4446, 4461, 4532 EOF #Registers are essentially unsigned numbers. */

/******************************************************************************
 *                      Include Files
 *****************************************************************************/
#include "kf8a100fxx_i2c.h"
#include "kf8a100fxx_uart.h"
/******************************************************************************
 *                      Macro Definitions
 *****************************************************************************/

/******************************************************************************
 *                      Constants
 *****************************************************************************/

/******************************************************************************
 *                      Type definitions
 *****************************************************************************/

/******************************************************************************
 *                      Variables
 *****************************************************************************/

/******************************************************************************
 *                      Function definitions
 *****************************************************************************/

/**
 * @brief I2C Initialization
 *
 * @param Mode I2C mode
 * @param AddrOrBaudRate The I2C slave mode is an address register with the high 7 bits active, and the I2C master mode
 * is a baud rate register with the low 7 bits active.
 * When the system clock frequency is 16MHz:
 * 100 kHz - 39 (theoretical error: 0.00%)
 * 150 kHz - 26 (theoretical error: 1.23%)
 * 400 kHz -  9 (theoretical error: 0.00%)
 */
void I2c_Init(I2c_ModeType Mode, I2c_Addr_BaudRate AddrOrBaudRate)
{
    SSCIEN   = 0u;
    SSCICTL0 = (uint8_t)Mode | 0x10u;
    SSCICTL1 = 0x00u;
    SSCISTA  = 0x00u;
    SSCIADD  = (uint8_t)AddrOrBaudRate;
    SSCIEN   = 1u;
}

/**
 * @brief I2C DeInitialization
 *
 */
void I2c_DeInit(void)
{
    SSCICTL0 = 0x00u;
    SSCICTL1 = 0x00u;
    SSCISTA  = 0x00u;
    SSCIADD  = 0x00u;
}

/**
 * @brief Enable or disable I2C/SPI/SSCIEN
 *
 * @param State 0: disable, 1: enable
 */
void I2c_Enable(uint8_t State)
{
    SSCIEN = (uint8_t)State;
}

/**
 * @brief I2c host initiates start signal
 *
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 1: I2C_START_TIMEOUT,
 */
I2c_StatusType I2c_Start(void)
{
    uint16_t       timeout = I2C_TIMEOUT_CONFIG;
    I2c_StatusType state   = I2C_OK;
    /* Send START. automatically cleared by hardware */
    STARTEN = 1u;
    while ((STARTEN == 1u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = I2C_START_TIMEOUT;
    }
    else
    {
        timeout = I2C_TIMEOUT_CONFIG;
        while ((SSCIIF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = I2C_START_TIMEOUT;
        }
        else
        {
            /* nothing */
        }
        SSCIIF = 0u;
    }

    return state;
}

/**
 * @brief I2c host initiates stop signal
 *
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 2: I2C_STOP_TIMEOUT,
 */
I2c_StatusType I2c_Stop(void)
{
    uint16_t       timeout = I2C_TIMEOUT_CONFIG;
    I2c_StatusType state   = I2C_OK;
    STOPEN                 = 1u;
    while ((STOPEN == 1u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = I2C_STOP_TIMEOUT;
    }
    else
    {
        timeout = I2C_TIMEOUT_CONFIG;
        while ((SSCIIF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = I2C_STOP_TIMEOUT;
        }
        else
        {
            /* nothing */
        }
        SSCIIF = 0u;
    }
    return state;
}

/**
 * @brief I2c host sends one byte of data
 *
 * @param c Single-byte data to be sent
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 4: I2C_WRITE_TIMEOUT,
 */
I2c_StatusType I2c_SendB(uint8_t c)
{
    uint16_t       timeout = I2C_TIMEOUT_CONFIG;
    I2c_StatusType state   = I2C_OK;
    SSCIBUFR               = c;
    /* Send completion SSCIBUF clear */
    while ((SSCIBUF == 1u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = I2C_WRITE_TIMEOUT;
    }
    else
    {
        timeout = I2C_TIMEOUT_CONFIG;
        /* Determine if an answer has been received */
        while ((SSCIACKSTA == 1u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = I2C_WRITE_TIMEOUT;
        }
        else
        {
            timeout = I2C_TIMEOUT_CONFIG;
            /* Wait for a single byte of data to be sent */
            while ((SSCIIF == 0u) && (timeout > 0u))
            {
                timeout = timeout - 1u;
            }
            if (timeout == 0u)
            {
                state = I2C_WRITE_TIMEOUT;
            }
            else
            {
                /* nothing */
            }
            SSCIIF = 0u;
        }
    }
    return state;
}

/**
 * @brief I2c host receives one byte of data
 *
 * @return uint8_t One byte of data received
 */
uint8_t I2c_RcvB(void)
{
    uint8_t  da      = 0u;
    uint16_t timeout = I2C_TIMEOUT_CONFIG;
    SSCIRCEN         = 1u;
    /* Hardware automatically clears when reception is complete */
    while ((SSCIRCEN == 1u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    /* Receive complete, SSCIIF set */
    timeout = I2C_TIMEOUT_CONFIG;
    while ((SSCIIF == 0u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    SSCIIF = 0u;

    da = SSCIBUFR;
    return da;
}

/**
 * @brief The I2c host sends an answer signal
 *
 * @param a 0 is an answer, 1 is no answer
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 3: I2C_ACK_TIMEOUT,
 */
I2c_StatusType I2c_Ack(I2c_AnsType a)
{
    uint16_t       timeout = I2C_TIMEOUT_CONFIG;
    I2c_StatusType state   = I2C_OK;
    /* Answer signal = 1, no answer; Answer signal = 0u, answer */
    /* PRQA S 4447 8 #Registers are essentially unsigned numbers. */
    if (a == I2C_NO_ANSWER)
    {
        SSCIACKDAT = (uint8_t)I2C_NO_ANSWER;
    }
    else
    {
        SSCIACKDAT = (uint8_t)I2C_ANSWER;
    }
    /* Enable answer signal transmission */
    SSCIACKEN = 1u;
    /* After sending ACKDAT, the hardware is automatically cleared to zero */
    while ((SSCIACKEN == 1u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = I2C_ACK_TIMEOUT;
    }
    else
    {
        timeout = I2C_TIMEOUT_CONFIG;
        while ((SSCIIF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = I2C_ACK_TIMEOUT;
        }
        else
        {
            /* nothing */
        }
        SSCIIF = 0u;
    }
    return state;
}

/**
 * @brief The I2c host sends multiple bytes in succession
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Cnt data length
 * @param Addr i2c slave address
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 1: I2C_START_TIMEOUT,
 * 2: I2C_STOP_TIMEOUT,
 * 3: I2C_ACK_TIMEOUT,
 * 4: I2C_WRITE_TIMEOUT,
 * 5: I2C_READ_TIMEOUT
 */
I2c_StatusType I2c_SendDataWrite(const uint8_t *Buf, uint8_t Cnt, uint8_t Addr)
{
    uint8_t        i          = 0u;
    I2c_StatusType state      = I2C_OK;
    uint8_t        Write_Addr = Addr & 0xfeu;

    if (I2c_Start() == I2C_START_TIMEOUT)
    {
        state = I2C_START_TIMEOUT;
    }
    else
    {
        /* Send 7-bit address */
        if (I2c_SendB(Write_Addr) == I2C_WRITE_TIMEOUT)
        {
            state = I2C_WRITE_TIMEOUT;
        }
        else
        {
            for (i = 0u; i < Cnt; i++)
            {
                if (I2c_SendB(Buf[i]) == I2C_WRITE_TIMEOUT)
                {
                    state = I2C_WRITE_TIMEOUT;
                    break;
                }
                else
                {
                    /* nothing */
                }
            }
        }

        if (I2c_Stop() == I2C_STOP_TIMEOUT)
        {
            state = I2C_STOP_TIMEOUT;
        }
        else
        {
            /* nothing */
        }
    }
    return state;
}

/**
 * @brief I2c host reads multiple bytes consecutively
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Cnt data length
 * @param Addr i2c slave address
 * @return I2c_StatusType
 * 0: I2C_OK,
 * 1: I2C_START_TIMEOUT,
 * 2: I2C_STOP_TIMEOUT,
 * 3: I2C_ACK_TIMEOUT,
 * 4: I2C_WRITE_TIMEOUT,
 * 5: I2C_READ_TIMEOUT
 */
I2c_StatusType I2c_SendDataRead(uint8_t *Buf, uint8_t Cnt, uint8_t Addr)
{
    uint8_t        i         = 0u;
    uint8_t        Read_Addr = Addr | 0x01u;
    I2c_StatusType state     = I2C_OK;

    if (I2c_Start() == I2C_START_TIMEOUT)
    {
        state = I2C_START_TIMEOUT;
    }
    else
    {
        if (I2c_SendB(Read_Addr) == I2C_WRITE_TIMEOUT)
        {
            state = I2C_WRITE_TIMEOUT;
        }
        else
        {
            for (i = 0u; i < (Cnt - 1u); i++)
            {
                Buf[i] = I2c_RcvB();
                if (I2c_Ack(I2C_ANSWER) == I2C_ACK_TIMEOUT)
                {
                    state = I2C_ACK_TIMEOUT;
                }
                else
                {
                    /* nothing */
                }
            }

            Buf[Cnt - 1u] = I2c_RcvB();
            if (I2c_Ack(I2C_NO_ANSWER) == I2C_ACK_TIMEOUT)
            {
                state = I2C_ACK_TIMEOUT;
            }
            else
            {
                /* nothing */
            }
        }
        if (I2c_Stop() == I2C_STOP_TIMEOUT)
        {
            state = I2C_STOP_TIMEOUT;
        }
        else
        {
            /* nothing */
        }
    }
    return state;
}

/* EOF */
